home *** CD-ROM | disk | FTP | other *** search
Text File | 2004-02-21 | 35.7 KB | 1,092 lines |
- # Copyright (c) 2001, Bryan Oakley
- # All Rights Reservered
- #
- # Bryan Oakley
- # oakley_at_bardo.clearlight.com
- #
- # tkwizard 1.0a1
- #
- # this code is freely distributable without restriction, and is
- # provided as-is with no warranty expressed or implied.
- #
-
- package require Tk 8.0
- package provide tkwizard 1.0
-
- # create the package namespace, and do some basic initialization
- namespace eval tkwizard {
-
- namespace export tkwizard
-
- set ns [namespace current]
-
- # define class bindings
- bind Wizard <<WizHelp>> [list ${ns}::handleEvent %W <<WizHelp>>]
- bind Wizard <<WizNextStep>> [list ${ns}::handleEvent %W <<WizNextStep>>]
- bind Wizard <<WizPrevStep>> [list ${ns}::handleEvent %W <<WizPrevStep>>]
- bind Wizard <<WizCancel>> [list ${ns}::handleEvent %W <<WizCancel>>]
- bind Wizard <<WizFinish>> [list ${ns}::handleEvent %W <<WizFinish>>]
-
- # create a default image
- image create photo [namespace current]::feather -data {
- R0lGODlhIAAgALMAANnZ2QAAwAAA/wBAwAAAAICAgAAAgGBggKCgpMDAwP//
- /////////////////////yH5BAEAAAAALAAAAAAgACAAAAT/EMhJq60hhHDv
- pVCQYohAIJBzFgpKoSAEAYcUIRAI5JSFlkJBCGLAMYYIIRAI5ASFFiqDgENK
- EUIwBAI5ywRlyhAEHFKKEEIgEMgJyiwUBAGHnCKEEAyBQM4yy5RhCDikFDBI
- SSCQExRKwxBDjAGHgEFKQyCQk9YgxBBjDAGDnAQCOWkNQgwxxDgwyGkIBHJS
- GoQQYohRYJDTEAjkpDWIIYQQBQY5A4FATlqDEEIMgWCQMxgCgZy0BiikRDDI
- GQyBQE5aAxRSIhjkNIRAICetAQop04BBTgOBnLTKIIQQacAgZzAQyEkrCEII
- kQYMckoDgZy0giCESAMGOaWBQMoydeeUQYhUYJBTGgikLHNOGYRACQY5pYFA
- yjLnnEGgNGCQMxgAACgFAjnpFEUNGOQ0BgI5Z6FUFlVgkJNAICctlMqiyggB
- BkMIBHLOUiidSUEiJwRyzlIopbJQSilFURJUIJCTVntlKhhjCwsEctJqr0wF
- Y0xhBAA7
- }
-
- # Make a class binding to do some housekeeping
- bind Wizard <Destroy> [list ${ns}::wizard-destroy %W]
- }
-
- # usage: tkwizard ?-showhelp boolean? ?-title string?
- proc tkwizard::tkwizard {name args} {
-
- set showHelp 0
- set body {}
-
- set i 0
- while {$i < [llength $args]} {
- set arg [lindex $args $i]
- switch -glob -- $arg {
- -showhelp {
- incr i
- set showHelp [lindex $args $i]
- }
- -title {
- incr i
- set title [lindex $args $i]
- }
- default {
- return -code error "unknown option \"$arg\" (!)"
- }
- }
- incr i
- }
-
- if {![info exists title]} {set title $name}
-
- init $name $showHelp $title
-
- return $name
- }
-
- ##
- # wizard-destroy
- #
- # does cleanup of the wizard when it is destroyed. Specifically,
- # it destroys the associated namespace
- #
- proc tkwizard::wizard-destroy {name} {
-
- upvar #0 [namespace current]::@$name-state wizState
-
- if {![info exists wizState]} {
- return -code error "unknown wizard \"$name\""
- }
- set w $wizState(window)
- interp alias {} $wizState(alias) {}
- catch {namespace delete $wizState(namespace)} message
-
- return ""
- }
-
-
- # intended for an end user to draw a step for the purpose
- # of measuring it's size. Not fully realized yet; it seems to
- # put the wizard in a slightly weird state
- proc tkwizard::wizProx-drawstep {name stepname} {
-
- upvar #0 [namespace current]::@$name-state wizState
- upvar #0 [namespace current]::@$name-config wizConfig
- upvar #0 [namespace current]::@$name-stepData wizStepData
-
- # First, build the appropriate layout...
- set layout $wizStepData($stepname,layout)
- buildLayout $name $layout
-
- # then build the step...
- set wizConfig(-step) $stepname
- buildStep $name $stepname
- }
-
- ##
- #
- proc tkwizard::wizProc-cget {name args} {
- upvar #0 [namespace current]::@$name-config wizConfig
-
- if {[llength $args] != 1} {
- return -code error "wrong \# args: should be \"$name cget option\""
- }
- set option [lindex $args 0]
- if {[info exists wizConfig($option)]} {
- return $wizConfig($option)
- }
- return -code error "unknown option \"$option\""
- }
-
- proc tkwizard::wizProc-configure {name args} {
- upvar #0 [namespace current]::@$name-config wizConfig
-
- if {[llength $args] == 0} {
- set result [list]
- foreach item [lsort [array names wizConfig]] {
- lappend result $item $wizConfig($item)
- }
- return $result
-
- } elseif {[llength $args] == 1} {
- uplevel $name cget [lindex $args 0]
-
- } else {
- foreach {option value} $args {
- if {![info exists wizConfig($option)]} {
- return -code error "unknown option \"$option\""
- }
- set wizConfig($option) $value
- switch -exact -- $option {
- -background {
- $wizConfig(toplevel) configure -background $value
- # in theory we should step through all widgets,
- # changing their color as well. Maybe I generate
- # a virtual event like <<WizConfigure>> so the
- # programmer can reconfigure their steps appropriately
- }
- -title {
- wm title $w $value
- }
- }
- }
- }
- }
-
- ##
- # wizProc
- #
- # this is the procedure that represents the wizard object; each
- # wizard will be aliased to this proc; the wizard name will be
- # provided as the first argument (this is transparent to the caller)
-
- proc tkwizard::wizProc {name command args} {
- # define the state variable here; that way the worker procs
- # can do an uplevel to access the variable with a simple name
- variable @$name-state
-
- # call the worker proc
- eval wizProc-$command $name $args
- }
-
- ##
- # wizProc-hide
- #
- # usage: wizHandle hide
- #
- # hides the wizard without destroying it. Note that state is NOT
- # guaranteed to be preserved, since a subsequent "show" will reset
- # the state.
-
- proc tkwizard::wizProc-hide {name args} {
- upvar #0 [namespace current]::@$name-state wizState
-
- wm withdraw $wizState(window)
- }
-
- ##
- # wizProc-order
- #
- # usage: wizHandle order ?-nocomplain? ?step step ...?
- #
- # example: wizHandle order step1 step2 step3 finalStep
- #
- # unless -nocomplain is specified, will throw an error if
- # a nonexistent step is given, or if a duplicate step is
- # given.
- #
- # without any steps, will return the current order
-
- proc tkwizard::wizProc-order {name args} {
- upvar #0 [namespace current]::@$name-state wizState
-
- set i [lsearch -exact $args "-nocomplain"]
- set complain 1
-
- if {$i >= 0} {
- set complain 0
- set args [lreplace $args $i $i]
- }
-
- if {$complain} {
- # make sure all of the steps are defined. "defined" means
- # there is a initialize proc for that step. We also need to
- # make sure we don't have the same step represented twice.
- # This is inefficient, but speed isn't particularly critical
- # here
- array set found [list]
- foreach step $args {
- set tmp [info commands $wizState(namespace)::initialize-$step]
- if {[llength $tmp] != 1} {
- return -code error "unknown step \"$step\""
- }
- if {[info exists found($step)]} {
- return -code error "duplicate step \"$step\""
- }
- set found($step) 1
- }
- }
-
- if {[llength $args] == 0} {
- return $wizState(steps)
- } else {
- set wizState(steps) $args
- }
- }
-
- ##
- # wizProc-step
- #
- # implements the "step" method of the wizard object. The body
- # argument is code that will be run when the step identified by
- # 'stepName' is to be displayed in the wizard
- #
- # usage: wizHandle step stepName ?-layout layout? body
- #
-
- proc tkwizard::wizProc-step {name stepName args} {
-
- upvar #0 [namespace current]::@$name-state wizState
- upvar #0 [namespace current]::@$name-stepData wizStepData
-
- set body [lindex $args end]
- set args [lreplace $args end end]
- # set args [lrange $args 0 end-1]
-
- set layout "basic"
- set i [lsearch -exact $args {-layout}]
- if {$i >= 0} {
- set j [expr {$i + 1}]
- set layout [lindex $args $j]
- if {[llength [info commands [namespace current]::buildLayout-$layout]] == 0} {
- return -code error "unknown layout \"$layout\""
- }
- set args [lreplace $args $i $j]
- }
- set wizStepData($stepName,layout) $layout
-
- lappend wizState(steps) $stepName
-
- set procname "[namespace current]::${name}::initialize-$stepName"
- proc $procname {} "[list set this $name];\n$body"
- }
-
- ##
- # wizProc-widget
- #
- # Returns the path to an internal widget, or executes the
- # an internal widget command
- #
- # usage: wizHandle widget widgetName ?args?
- #
- # if [llength $args] > 0 it will run the widget command with
- # the args. Otherwise it will return the widget path
-
- proc tkwizard::wizProc-widget {name args} {
- upvar #0 [namespace current]::@$name-state wizState
-
- if {[llength $args] == 0} {
- # return a list of all widget names
- set result [list]
- foreach item [array names wizState widget,*] {
- regsub {widget,} $item {} item
- lappend result $item
- }
- return $result
- }
-
- set widgetname [lindex $args 0]
- set args [lrange $args 1 end]
-
- if {![info exists wizState(widget,$widgetname)]} {
- return -code error "unknown widget: \"$widgetname\""
- }
-
- if {[llength $args] == 0} {
- return $wizState(widget,$widgetname)
- }
-
- # execute the widget command
- eval [list $wizState(widget,$widgetname)] $args
- }
-
- ##
- # wizProc-info
- #
- # Returns the information in the state array
- #
- # usage: wizHandle info
-
- proc tkwizard::wizProc-info {name args} {
-
- if {[llength $args] > 0} {
- return -code error "wrong \# args: should be \"$name info\""
- }
- upvar #0 [namespace current]::@$name-state wizState
-
- foreach item [lsort [array names wizState]] {
- puts "$item = $wizState($item)"
- }
- }
-
- # return the namespace of the wizard
- proc tkwizard::wizProc-namespace {name} {
- set ns [namespace current]::${name}
- return $ns
- }
-
- # execute the code in the namespace of the wizard
- proc tkwizard::wizProc-eval {name code} {
- set ns [namespace current]::${name}
- namespace eval $ns $code
- }
-
- ##
- # wizProc-show
- #
- # Causes the wizard to be displayed in it's initial state
- #
- # usage: wizHandle show
- #
- # This is where all of the widgets are created, though eventually
- # I'll probably move the widget drawing to a utility proc...
-
- proc tkwizard::wizProc-show {name args} {
-
- upvar #0 [namespace current]::@$name-state wizState
- upvar #0 [namespace current]::@$name-config wizConfig
-
- # initialize the remainder of the wizard state
- set wizState(history) [list]
- set wizConfig(-previousstep) ""
- set wizConfig(-nextstep) ""
-
- set steps $wizState(steps)
- if {[llength $steps] == 0} {
- # no steps? Just show it as-is.
- wm deiconify $name
- return
- }
-
- # set a trace on where we store the next state. The trace
- # will cause the next and previous buttons to become
- # enabled or disabled. Thus, within a step a programmer can
- # decide when to enable or disable the buttons by merely
- # setting these variables.
- set code [namespace code "varTrace [list $name]"]
- set stateVar "[namespace current]::@$name-config"
- foreach item {-previousstep -nextstep -state -complete} {
- trace vdelete ${stateVar}($item) wu $code
- trace variable ${stateVar}($item) wu $code
- }
-
- # show the first step
- set wizState(history) [lindex $steps 0]
- showStep $name
-
- # make it so, Number One
- update idletasks
- wm deiconify $wizState(window)
-
- # This makes sure closing the window with the window manager control
- # Does The Right Thing (now if only I could figure out what the
- # Right Thing is...)
- wm protocol $name WM_DELETE_WINDOW \
- [list $wizState(widget,cancelButton) invoke]
-
- return ""
- }
-
- # This gets called whenever certain parts of our state variable
- # get set or unset (presently this only happens with -nextstep
- # and -previousstep)
- proc tkwizard::varTrace {name varname index op} {
- upvar #0 [namespace current]::@$name-state wizState
- upvar #0 [namespace current]::@$name-config wizConfig
-
- catch {
- switch -- $index {
- -state {
- set state $wizConfig(-state)
- if {[string equal $state "normal"]} {
- # $name configure -cursor {}
- if {[string length $wizConfig(-previousstep)] == 0} {
- $wizState(widget,backButton) configure -state disabled
- } else {
- $wizState(widget,backButton) configure -state normal
- }
- if {[string length $wizConfig(-nextstep)] == 0} {
- $wizState(widget,nextButton) configure -state disabled
- } else {
- $wizState(widget,nextButton) configure -state normal
- }
- if {$wizConfig(-complete)} {
- $wizState(widget,finishButton) configure -state normal
- } else {
- $wizState(widget,finishButton) configure -state disabled
- }
-
- } else {
- # $name configure -cursor watch
- $wizState(widget,cancelButton) configure -cursor left_ptr
- $wizState(widget,nextButton) configure -state disabled
- $wizState(widget,backButton) configure -state disabled
- $wizState(widget,helpButton) configure -state disabled
- $wizState(widget,finishButton) configure -state disabled
- }
- }
- -complete {
- if {$wizConfig(-complete)} {
- $wizState(widget,finishButton) configure -state normal
- } else {
- $wizState(widget,finishButton) configure -state disabled
- }
- }
-
- -previousstep {
- set state normal
- if {[string length $wizConfig(-previousstep)] == 0} {
- set state disabled
- }
- $wizState(widget,backButton) configure -state $state
- }
- -nextstep {
- set state normal
- if {[string length $wizConfig(-nextstep)] == 0} {
- set state disabled
- }
- $wizState(widget,nextButton) configure -state $state
- }
-
- default {
- puts "bogus variable trace: name=$varname index=$index op=$op"
- }
- }
- }
- }
-
- # Causes a step to be built by clearing out the current contents of
- # the client window and then executing the initialization code for
- # the given step
-
- proc tkwizard::buildStep {name step} {
- upvar #0 [namespace current]::@$name-state wizState
-
- # reset the state of the windows in the wizard
- eval destroy [winfo children $wizState(widget,clientArea)]
- # wizProc-stepconfigure $name -title "" -subtitle "" -pretext "" -posttext ""
-
- namespace eval $wizState(namespace) initialize-$step
-
- }
-
-
- # This block of code is common to all wizard actions.
- # (ie: it is the target of the -command option for wizard buttons)
- proc tkwizard::cmd {command name} {
-
- upvar #0 [namespace current]::@$name-state wizState
- upvar #0 [namespace current]::@$name-config wizConfig
-
- switch $command {
- Help {event generate $name <<WizHelp>>}
- Next {event generate $name <<WizNextStep>>}
- Previous {event generate $name <<WizPrevStep>>}
- Finish {event generate $name <<WizFinish>>}
- Cancel {event generate $name <<WizCancel>>}
-
- default {
- puts "'$command' not implemented yet"
- }
- }
- }
-
- proc tkwizard::handleEvent {name event} {
-
- upvar #0 [namespace current]::@$name-state wizState
- upvar #0 [namespace current]::@$name-config wizConfig
- upvar #0 [namespace current]::@$name-stepData wizStepData
-
- switch $event {
- <<WizHelp>> {
- # not implemented yet
- }
-
- <<WizNextStep>> {
- set thisStep [lindex $wizState(history) end]
- lappend wizState(history) $wizConfig(-nextstep)
- showStep $name
- }
-
- <<WizPrevStep>> {
-
- # pop an item off of the history
- set p [expr {[llength $wizState(history)] -2}]
- set wizState(history) [lrange $wizState(history) 0 $p]
- showStep $name
- }
-
- <<WizFinish>> {
-
- set thisStep [lindex $wizState(history) end]
- wizProc-hide $name
- }
-
- <<WizCancel>> {
-
- wizProc-hide $name
- }
-
- default {
- puts "'$event' not implemented yet"
- }
- }
- }
-
- proc tkwizard::showStep {name} {
-
- upvar #0 [namespace current]::@$name-state wizState
- upvar #0 [namespace current]::@$name-config wizConfig
- upvar #0 [namespace current]::@$name-stepData wizStepData
-
- # the step is whatever is at the tail end of our
- # history
- set step [lindex $wizState(history) end]
- set proc "initialize-$step"
- set wizConfig(-step) $step
-
- set layout $wizStepData($step,layout)
-
- # First, build the appropriate layout...
- buildLayout $name $layout
-
- # then build the step...
- set steps $wizState(steps)
- set lastStep [expr {[llength $steps] -1}]
- set stepIndex [lsearch $steps $step]
- set prevIndex [expr {$stepIndex -1}]
- set nextIndex [expr {$stepIndex + 1}]
-
- # initialize the next, previous and current step configuration
- # options; this will set the state of the next/previous buttons.
- # note that the user can retrieve these values with the normal
- # 'cget' and 'configure' methods
- set p [expr {[llength $wizState(history)] -2}]
- set wizConfig(-previousstep) [lindex $wizState(history) $p]
- set wizConfig(-nextstep) [lindex $steps $nextIndex]
-
- if {$stepIndex == ([llength $steps]-1)} {
- set wizConfig(-complete) 1
- } else {
- set wizConfig(-complete) 0
- }
-
- buildStep $name $step
-
- }
-
-
- proc tkwizard::init {name showHelp title} {
-
- # name should be a widget path
- set w $name
-
- # create variables in this namespace to keep track
- # of the state of this wizard. We do this here to
- # avoid polluting the namespace of the widget. We'll
- # create local aliases for the variables to make the
- # code easier to read and write
-
- # this variable contains state information about the
- # wizard, such as the wizard title, the name of the
- # window and namespace associated with the wizard, the
- # list of steps, and so on.
- variable "@$name-state"
- upvar \#0 [namespace current]::@$name-state wizState
-
- # this variable contains all of the parameters associated
- # with the wizard and settable with the "configure" method
- variable "@name-config"
- upvar \#0 [namespace current]::@$name-config wizConfig
-
- # this is an experimental array containing data of known
- # step types. Presently not being used.
- variable "@name-stepTypes"
- upvar \#0 [namespace current]::@$name-stepTypes wizStepTypes
-
- # this contains step-specific data, such as the step title
- # and subtitle, icon, etc. All elements are unset prior to
- # rendering a given step. It is each step's responsibility
- # to set it appropriately, and it is each step type's
- # responsibility to use the data.
- variable "@name-stepData"
- upvar \#0 [namespace current]::@$name-stepData wizStepData
-
- # do some state initialization; more will come later when
- # the wizard is actually built
- set wizConfig(-complete) 0
- set wizConfig(-state) normal
- set wizConfig(-title) $title
- set wizConfig(-nextstep) ""
- set wizConfig(-previousstep) ""
- set wizConfig(-step) ""
- set wizConfig(-showhelp) $showHelp
-
- set wizState(title) $title
- set wizState(window) $w
- set wizState(steps) [list]
- set wizState(namespace) [namespace current]::$name
- set wizState(name) $name
- set wizState(toplevel) {}
-
- # create the wizard (except for the step pages...)
- buildDialog $name
-
- # this establishes a namespace for this wizard; this namespace
- # will contain wizard-specific data managed by the creator of
- # the wizard
- namespace eval $name {}
-
- # this creates the instance command by first renaming the widget
- # command associated with our toplevel, then making an alias
- # to our own command
- set wizState(toplevel) $wizState(namespace)::originalWidgetCommand
- rename $w $wizState(toplevel)
- interp alias {} ::$w {} [namespace current]::wizProc $name
- set wizState(alias) ::$w
-
- # set some useful configuration values
- set wizConfig(-background) \
- [$wizState(namespace)::originalWidgetCommand cget -background]
- }
-
- proc tkwizard::buildDialog {name} {
- # This is custom for Getleft
- global labelButtons
-
- upvar #0 [namespace current]::@$name-state wizState
- upvar #0 [namespace current]::@$name-config wizConfig
-
- set prefix [string trimright $wizState(window) .]
-
- set wizState(widget,topframe) $prefix.topframe
- set wizState(widget,sep1) $prefix.sep1
- set wizState(widget,sep2) $prefix.sep2
- set wizState(widget,buttonFrame) $prefix.buttonFrame
- set wizState(widget,helpButton) $prefix.buttonFrame.helpButton
- set wizState(widget,nextButton) $prefix.buttonFrame.nextButton
- set wizState(widget,backButton) $prefix.buttonFrame.backButton
- set wizState(widget,cancelButton) $prefix.buttonFrame.cancelButton
- set wizState(widget,finishButton) $prefix.buttonFrame.finishButton
- set wizState(widget,layoutFrame) $prefix.layoutFrame
-
- # create the toplevel window
- set w $wizState(window)
- toplevel $w -class Wizard -bd 2 -relief groove
- wm title $w $wizConfig(-title)
- wm withdraw $w
- wm resizable $w 0 0
-
- # the dialog is composed of two areas: the row of buttons and the
- # area with the dynamic content. To make it look the way we want it to
- # we'll use another frame for a visual separator
- frame $wizState(widget,buttonFrame) -bd 0
- frame $wizState(widget,layoutFrame) -bd 0
- frame $wizState(widget,sep1) -class WizSeparator -height 2 -bd 2 -relief groove
-
- pack $wizState(widget,buttonFrame) -side bottom -fill x
- pack $wizState(widget,sep1) -side bottom -fill x
- pack $wizState(widget,layoutFrame) -side top -fill both -expand y
-
- # make all of the buttons
- button $wizState(widget,helpButton) \
- -text "What's This?" \
- -default normal \
- -bd 1 \
- -relief raised \
- -command [namespace code "cmd Help [list $name]"]
-
- button $wizState(widget,backButton) \
- -textvariable labelButtons(back) \
- -default normal \
- -width 9 \
- -bd 1 \
- -relief raised \
- -command [namespace code "cmd Previous [list $name]"]
-
- button $wizState(widget,nextButton) \
- -textvariable labelButtons(next) \
- -default normal \
- -width 9 \
- -bd 1 \
- -relief raised \
- -command [namespace code "cmd Next [list $name]"]
-
- button $wizState(widget,finishButton) \
- -textvariable labelButtons(finish) \
- -default normal \
- -width 9 \
- -bd 1 \
- -relief raised \
- -command [namespace code "cmd Finish [list $name]"]
-
- button $wizState(widget,cancelButton) \
- -textvariable labelButtons(cancel) \
- -default normal \
- -width 9 \
- -bd 1 \
- -relief raised \
- -command [namespace code "cmd Cancel [list $name]"]
-
- # pack the buttons
- if {$wizConfig(-showhelp)} {
- pack $wizState(widget,helpButton) -side left -padx 4 -pady 8
- }
- pack $wizState(widget,cancelButton) -side right -padx 4 -pady 8
- pack $wizState(widget,finishButton) -side right -pady 8 -padx 4
- pack $wizState(widget,nextButton) -side right -pady 8
- pack $wizState(widget,backButton) -side right -pady 8
-
- # return the name of the toplevel, for lack of a better idea...
- return $wizState(window)
- }
-
- proc tkwizard::buildLayout {name layoutName} {
- upvar #0 [namespace current]::@$name-state wizState
- upvar #0 [namespace current]::@$name-config wizConfig
-
- set w $wizState(window)
- set lf $wizState(widget,layoutFrame)
-
- # initialize the layout variables
- initLayout-$layoutName $name
-
- # if the layout hasn't actually been built yet, build it
- if {![winfo exists $lf.$layoutName]} {
- buildLayout-$layoutName $name
- }
- eval pack forget [winfo children $lf]
- pack $lf.$layoutName -side top -fill both -expand y
-
- }
-
- # this is a user-callable interface to configureLayout-<layout>
- proc tkwizard::wizProc-stepconfigure {name args} {
- upvar #0 [namespace current]::@$name-state wizState
- upvar #0 [namespace current]::@$name-config wizConfig
- upvar #0 [namespace current]::@$name-stepData wizStepData
-
- set step $wizConfig(-step)
- set layout $wizStepData($step,layout)
- eval configureLayout-$layout $name $args
- }
-
-
- # this defines the widget paths. Will be called each time we
- # switch layouts
- proc tkwizard::initLayout-basic {name} {
- upvar #0 [namespace current]::@$name-state wizState
- upvar #0 [namespace current]::@$name-config wizConfig
-
- set layout $wizState(widget,layoutFrame).basic
-
- set wizState(widget,clientArea) $layout.clientArea
- set wizState(widget,icon) $layout.icon
- set wizState(widget,title) $layout.title
- set wizState(widget,subtitle) $layout.subtitle
- set wizState(widget,pretext) $layout.pretext
- set wizState(widget,posttext) $layout.posttext
-
- }
-
- proc tkwizard::buildLayout-basic {name} {
- upvar #0 [namespace current]::@$name-state wizState
- upvar #0 [namespace current]::@$name-config wizConfig
-
- set layout $wizState(widget,layoutFrame).basic
- frame $layout -class WizLayoutBasic
-
- # using the option database saves me from hard-coding it for
- # every widget. I guess I'm just lazy.
- option add *WizLayoutBasic*Label.justify left interactive
- option add *WizLayoutBasic*Label.anchor nw interactive
- option add *WizLayoutBasic*Label.highlightThickness 0 interactive
- option add *WizLayoutBasic*Label.borderWidth 0 interactive
- option add *WizLayoutBasic*Label.padX 5 interactive
-
- # Client area. This is where the caller places its widgets.
- frame $wizState(widget,clientArea) -bd 8 -relief flat
- frame $layout.sep1 -class WizSeparator -height 2 -bd 2 -relief groove
-
- # title and subtitle and icon
- frame $layout.titleframe -bd 4 -relief flat -background white
- label $wizState(widget,title) -background white -width 40
- label $wizState(widget,subtitle) -height 2 -background white -padx 15 -width 40
- label $wizState(widget,icon) \
- -borderwidth 0 \
- -image [namespace current]::feather \
- -background white \
- -anchor c
- set labelfont [font actual [$wizState(widget,title) cget -font]]
- $wizState(widget,title) configure -font [concat $labelfont -weight bold]
-
- # put the title, subtitle and icon inside the frame we've
- # built for them
- set tf $layout.titleframe
- grid $wizState(widget,title) -in $tf -row 0 -column 0 -sticky nsew
- grid $wizState(widget,subtitle) -in $tf -row 1 -column 0 -sticky nsew
- grid $wizState(widget,icon) -in $tf -row 0 -column 1 -rowspan 2 -padx 8
- grid columnconfigure $tf 0 -weight 1
- grid columnconfigure $tf 1 -weight 0
-
- # pre and post text. We'll pick rough estimates on the size of these
- # areas. I noticed that if I didn't give it a width and height and a
- # step defined a really, really long string, the label would try to
- # accomodate the longest string possible, making the widget unnaturally
- # wide.
-
- label $wizState(widget,pretext) -width 40
- label $wizState(widget,posttext) -width 40
-
- # when our label widgets change size we want to reset the
- # wraplength to that same size.
- foreach widget {title subtitle pretext posttext} {
- bind $wizState(widget,$widget) <Configure> {
- # yeah, I know this looks weird having two after idle's, but
- # it helps prevent the geometry manager getting into a tight
- # loop under certain circumstances
- #
- # note that subtracting 10 is just a somewhat arbitrary number
- # to provide a little padding...
- after idle {after idle {%W configure -wraplength [expr {%w -10}]}}
- }
- }
-
- grid $layout.titleframe -row 0 -column 0 -sticky nsew -padx 0
- # grid $wizState(widget,title) -row 0 -column 0 -sticky nsew -padx 0
- # grid $wizState(widget,subtitle) -row 1 -column 0 -sticky nsew -padx 0
- # grid $wizState(widget,icon) -row 0 -column 1 -rowspan 2 -sticky nsew -ipadx 10 -ipady 4
- grid $layout.sep1 -row 1 -sticky ew
- grid $wizState(widget,pretext) -row 2 -sticky nsew -pady 8 -padx 8
- grid $wizState(widget,clientArea) -row 3 -sticky nsew -padx 8 -pady 8
- grid $wizState(widget,posttext) -row 4 -sticky nsew -pady 8 -pady 8
-
- grid columnconfigure $layout 0 -weight 1
- grid rowconfigure $layout 0 -weight 0
- grid rowconfigure $layout 1 -weight 0
- grid rowconfigure $layout 2 -weight 0
- grid rowconfigure $layout 3 -weight 1
- grid rowconfigure $layout 4 -weight 0
-
- # the pre and post text will initially not be visible. They will pop into
- # existence if they are configured to have a value
- grid remove $wizState(widget,pretext) $wizState(widget,posttext)
-
- }
-
- # usage: configureLayout-basic ?-title string? ?-subtitle string? ?-icon image?
- proc tkwizard::configureLayout-basic {name args} {
- upvar #0 [namespace current]::@$name-state wizState
- upvar #0 [namespace current]::@$name-config wizConfig
-
- if {[llength $args]%2 == 1} {
- return -code error "wrong number of args..."
- }
-
- foreach {option value} $args {
- switch -- $option {
- -title {
- $wizState(widget,title) configure -text "$value"
- }
-
- -subtitle {
- $wizState(widget,subtitle) configure -text $value
- }
-
- -icon {
- $wizState(widget,icon) configure -image $value
- }
-
- -pretext {
- $wizState(widget,pretext) configure -text $value
- if {[string length $value] > 0} {
- grid $wizState(widget,pretext)
-
- } else {
- grid remove $wizState(widget,pretext)
- }
- }
-
- -posttext {
- $wizState(widget,posttext) configure -text $value
- if {[string length $value] > 0} {
- grid $wizState(widget,posttext)
- } else {
- grid remove $wizState(widget,posttext)
- }
- }
-
- default {
- return -code error "unknown option \"$option\""
- }
- }
- }
- }
-
- ######
- # "Advanced" layout. Nothing really advanced about it, but that's what
- # microsoft seems to call wizards that look like this. Go figure.
- ######
-
- proc tkwizard::initLayout-advanced {name} {
- upvar #0 [namespace current]::@$name-state wizState
- upvar #0 [namespace current]::@$name-config wizConfig
-
- set layout $wizState(widget,layoutFrame).advanced
-
- set wizState(widget,clientArea) $layout.clientArea
- set wizState(widget,icon) $layout.icon
- set wizState(widget,title) $layout.title
- set wizState(widget,subtitle) $layout.subtitle
- set wizState(widget,pretext) $layout.pretext
- set wizState(widget,posttext) $layout.posttext
- }
-
- proc tkwizard::buildLayout-advanced {name} {
- upvar #0 [namespace current]::@$name-state wizState
- upvar #0 [namespace current]::@$name-config wizConfig
-
- set layout $wizState(widget,layoutFrame).advanced
-
- frame $layout -class WizLayoutAdvanced
-
- # using the option database saves me from hard-coding it for
- # every widget. I guess I'm just lazy.
- option add *WizLayoutAdvanced*Label.justify left interactive
- option add *WizLayoutAdvanced*Label.anchor nw interactive
- option add *WizLayoutAdvanced*Label.highlightThickness 0 interactive
- option add *WizLayoutAdvanced*Label.borderWidth 0 interactive
- option add *WizLayoutAdvanced*Label.padX 5 interactive
-
- # Client area. This is where the caller places its widgets.
- frame $wizState(widget,clientArea) -bd 8 -relief flat
- frame $layout.sep1 -class WizSeparator -height 2 -bd 2 -relief groove
-
- # title and subtitle
- label $wizState(widget,title)
- label $wizState(widget,subtitle) -height 2
- array set labelfont [font actual [$wizState(widget,title) cget -font]]
- set labelfont(-weight) bold
- incr labelfont(-size) 6
- $wizState(widget,title) configure -font [array get labelfont]
-
- # pre and post text.
- label $wizState(widget,pretext)
- label $wizState(widget,posttext)
-
- # when our label widgets change size we want to reset the
- # wraplength to that same size.
- foreach widget {title subtitle pretext posttext} {
- bind $wizState(widget,$widget) <Configure> {
- # yeah, I know this looks weird having two after idle's, but
- # it helps prevent the geometry manager getting into a tight
- # loop under certain circumstances
- #
- # note that subtracting 10 is just a somewhat arbitrary number
- # to provide a little padding...
- after idle {after idle {%W configure -wraplength [expr {%w -10}]}}
- }
- }
-
- # icon
- label $wizState(widget,icon) \
- -borderwidth 1 \
- -relief sunken \
- -image [namespace current]::feather \
- -background white \
- -anchor c \
- -width 96
-
- grid $wizState(widget,icon) -row 0 -column 0 -rowspan 5 -sticky nsew -pady 8 -padx 8
- grid $wizState(widget,title) -row 0 -column 1 -sticky ew -pady 8 -padx 8
- grid $wizState(widget,subtitle) -row 1 -column 1 -sticky ew -pady 8 -padx 8
- grid $wizState(widget,pretext) -row 2 -column 1 -sticky ew -padx 8
- grid $wizState(widget,clientArea) -row 3 -column 1 -sticky nsew -padx 8
- grid $wizState(widget,posttext) -row 4 -column 1 -sticky ew -padx 8 -pady 24
-
- grid columnconfigure $layout 0 -weight 0
- grid columnconfigure $layout 1 -weight 1
-
- grid rowconfigure $layout 0 -weight 0
- grid rowconfigure $layout 1 -weight 0
- grid rowconfigure $layout 2 -weight 0
- grid rowconfigure $layout 3 -weight 1
- grid rowconfigure $layout 4 -weight 0
-
- # the pre and post text will initially not be visible. They will pop into
- # existence if they are configured to have a value
- grid remove $wizState(widget,pretext) $wizState(widget,posttext)
- }
-
- proc tkwizard::configureLayout-advanced {name args} {
- upvar #0 [namespace current]::@$name-state wizState
- upvar #0 [namespace current]::@$name-config wizConfig
-
- if {[llength $args]%2 == 1} {
- return -code error "wrong number of args..."
- }
-
- foreach {option value} $args {
- switch -- $option {
- -title {
- $wizState(widget,title) configure -text $value
- }
-
- -subtitle {
- $wizState(widget,subtitle) configure -text $value
- }
-
- -icon {
- $wizState(widget,icon) configure -image $value
- }
-
- -pretext {
- $wizState(widget,pretext) configure -text $value
- if {[string length $value] > 0} {
- grid $wizState(widget,pretext)
- } else {
- grid remove $wizState(widget,pretext)
- }
- }
-
- -posttext {
- $wizState(widget,posttext) configure -text $value
- if {[string length $value] > 0} {
- grid $wizState(widget,posttext)
- } else {
- grid remove $wizState(widget,posttext)
- }
- }
-
- default {
- return -code error "unknown option \"$option\""
- }
- }
- }
- }
-
-